package com.odontosis.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.odontosis.as.OdontosisApplicationService;
import com.odontosis.compare.ComparadorPagamento;
import com.odontosis.dao.ServicoDAO;
import com.odontosis.entidade.Pagamento;
import com.odontosis.entidade.Servico;
import com.odontosis.entidade.TipoServico;
import com.odontosis.ioc.ContainerIoc;
import com.odontosis.util.HibernateUtil;
import com.odontosis.util.StringUtilsOdontosis;

/**
 * 
 * @author pablo
 * 
 */
public class ServicoService extends OdontosisApplicationService<Servico> {

	private ServicoDAO servicoDAO = new ServicoDAO();
	
	public ServicoService() throws Exception {
		super(Servico.class, new ServicoDAO());
		
	}
	
	public Collection<Servico> buscarServicosPorPacienteTipo(String nomePaciente, TipoServico tipoServico,String numeroPasta ,boolean orcamento){
		return servicoDAO.buscarServicoPorPacienteTipo(nomePaciente, tipoServico,numeroPasta, orcamento);
	}
	
	public List<Object[]> relatorioServicoPeriodo(Date dataInicial, Date dataFinal, boolean servico){
		return servicoDAO.relatorioServicoPeriodo(dataInicial, dataFinal, servico);
	}
	
	public List<Servico> relatorioServicoPorPeriodo(Date dataInicial, Date dataFinal, boolean servico){
		return servicoDAO.relatorioServicoPorPeriodo(dataInicial, dataFinal, servico);
	}
	

	@Override
	public void excluirLogicamente(Servico servico){
		PagamentoService pagamentoService = null;
		try{
			pagamentoService= ContainerIoc.getPagamentoService();
		}catch (Exception e) {
			e.printStackTrace();
		}
		//exclui todas os pagamentos associados ao serviço informado
//		Session session = HibernateUtil.currentSession();
//		Transaction transaction = session.beginTransaction();
		try {
			for(Pagamento pagamento : servico.getListaPagamentos()){
				pagamentoService.excluirLogicamente(pagamento);
			}
			servico.setDataCancelamento(new Date());
			servicoDAO.excluirLogicamente(servico);
		
		} catch (Exception e) {
		
			e.printStackTrace();
			throw new RuntimeException("ERRO ao exluir serviço.");
		}
	}
	
	public void excluirLogicamenteSemData(Servico servico){
		PagamentoService pagamentoService = null;
		try{
			pagamentoService= ContainerIoc.getPagamentoService();
		}catch (Exception e) {
			e.printStackTrace();
		}
		//exclui todas os pagamentos associados ao serviço informado
		try {
			for(Pagamento pagamento : servico.getListaPagamentos()){
				pagamentoService.excluirLogicamente(pagamento);
			}
			servicoDAO.excluirLogicamente(servico);
		
		} catch (Exception e) {			
			e.printStackTrace();
			throw new RuntimeException("ERRO ao exluir serviço.");
		}
	}
	
	

	/**
	 * Grava um serviço e gera as parcelas
	 * caso seja do tipo manutenção gera as parcelas iniciais com seus respectivos valores
	 * @param entidade
	 * @param alteracao
	 */
	public void saveOrUpdate(Servico entidade, Long alteracao, boolean isentar) {
		if(alteracao != null){
//			entidade.setListaPagamentos(load(alteracao).getListaPagamentos());
//			for(Pagamento pagamento : load(alteracao).getListaPagamentos()){
//				pagamento.setServico(entidade);
//			}
		}
		
		
		HibernateUtil.closeSession();		
		Session session = HibernateUtil.currentSession();
		Transaction transaction = session.beginTransaction();
		
		//if(!isentar){
			try {
				entidade.setDataCadastro(new Date());
				entidade.setIsento(isentar);
				
				/*retira falhas em entidade*/
				if(StringUtilsOdontosis.isVazia(entidade.getValorInicial()) || entidade.getValorInicial().equals("0")) {
					entidade.setValorInicial("0");
					entidade.setQuantidadeInicial("0");
				}
				if(StringUtilsOdontosis.isVazia(entidade.getQuantidadeInicial()) || entidade.getQuantidadeInicial().equals("0")) {
					entidade.setQuantidadeInicial("0");
					entidade.setValorInicial("0");
				}
				
				session.saveOrUpdate(entidade);
				if(!entidade.isOrcamento() ){
					if (entidade.getTipoServico() == TipoServico.MANUTENCAO) {
						// gerar  parcelas iniciais
						int mes = entidade.getMesVencimentoPrimeiraParcela() -1;
						int ano = entidade.getAnoVencimentoPrimeiraParcela();
						int parcelasIniciais = Integer.parseInt(entidade.getQuantidadeInicial());
						for (int i = 0; i <= parcelasIniciais ; i++) {
							Pagamento pagamento = new Pagamento();
							mes = mes + 1;
							// caso o mes seja maior que dezembro incrementa o ano e
							// volta para janeiro o mes
							if (mes == 13) {
								ano++;
								mes = 1;
							}
							pagamento.setAnoVencimento(ano);
							pagamento.setMesVencimento(mes);
							pagamento.setPago(false);
							pagamento.setServico(entidade);
							if(i == parcelasIniciais) {
								pagamento.setValor(entidade.getValor().doubleValue());
							} else {
								pagamento.setValor(Double.parseDouble(entidade.getValorInicial()));
							}
							session.saveOrUpdate(pagamento);
						}
						
						/*caso o número de parcelas iniciais seja zero
						cria uma parcela normal no primeiro vencimento par estimular a geração
						das demais parcelas */
						if(parcelasIniciais == 0) {
							Pagamento pagamento = new Pagamento();
							pagamento.setAnoVencimento(entidade.getAnoVencimentoPrimeiraParcela());
							pagamento.setMesVencimento(entidade.getMesVencimentoPrimeiraParcela());
							pagamento.setPago(false);
							pagamento.setServico(entidade);
							pagamento.setValor(entidade.getValor().doubleValue());
							session.saveOrUpdate(pagamento);
						}
		
					} else {
						BigDecimal valorPrestacao = entidade.getValor().divide(
								new BigDecimal(entidade.getQuantidadeParcelas()), BigDecimal.ROUND_HALF_EVEN);
						int mes = entidade.getMesVencimentoPrimeiraParcela().intValue() - 1;
						int ano = entidade.getAnoVencimentoPrimeiraParcela();
						for (int i = 0; i <= entidade.getQuantidadeParcelas().intValue() - 1; i++) {
							Pagamento pagamento = new Pagamento();
							mes = mes + 1;
							// caso o mes seja maior que dezembro incrementa o ano e
							// volta para janeiro o mes
							if (mes == 13) {
								ano++;
								mes = 1;
							}
							pagamento.setAnoVencimento(ano);
							pagamento.setMesVencimento(mes);
							pagamento.setPago(false);
							pagamento.setServico(entidade);
							pagamento.setValor(valorPrestacao.doubleValue());
							session.saveOrUpdate(pagamento);
						}
		
					}
				}
				transaction.commit();
			} catch (Exception e) {
				transaction.rollback();
				throw new RuntimeException("ERRO ao Salvar Serviço");
			}
		//}else{
//			//isentar
//			try{
//			for(Pagamento pagamento : entidade.getListaPagamentos()){
//				if((pagamento.getMesVencimento().intValue() >= entidade.getMesIsencao().intValue() && pagamento.getAnoVencimento().intValue() >= entidade.getAnoIsencao().intValue()) || pagamento.getAnoVencimento().intValue() > entidade.getAnoIsencao().intValue()){
//					if(!pagamento.isPago()){
//						pagamento.setAtivo(false);
//						pagamento.setServico(entidade);
//						session.update(pagamento);
//					}
//				}
//			}
//			transaction.commit();
//			}catch (Exception e) {
//				transaction.rollback();
//			}
//		}
		
		if(alteracao != null){
			excluirLogicamenteSemData(load(alteracao));
		}

	}
	
	public double obterSaldoDevedor( Pagamento pagamentoInicio) {
		List<Pagamento> pagamentos = pagamentoInicio.getServico().getListaPagamentos();
		double retorno = 0.0;
		Collections.sort(pagamentos, new ComparadorPagamento());
		Calendar dataPagamento = Calendar.getInstance();
		dataPagamento.set(pagamentoInicio.getAnoVencimento(), pagamentoInicio.getMesVencimento(), 1);
		for (Pagamento pagamento2 : pagamentos) {
			
			Calendar dataComparado = Calendar.getInstance();
			dataComparado.set(pagamento2.getAnoVencimento(), pagamento2.getMesVencimento(), 1);
			
			if(dataComparado.getTimeInMillis() >= dataPagamento.getTimeInMillis() || pagamentoInicio.equals(pagamento2)) {
				if(!pagamento2.isPago() && pagamento2.isAtivo()) {
					retorno += pagamento2.getValor();
				}
			}
		}
		
		return retorno;
		
	}
	
}
